package com.youhome.common;

import com.youhome.model.Log;
import com.youhome.model.User;
import com.youhome.service.LogService;
import com.youhome.service.TokenService;
import com.youhome.service.UserService;
import com.youhome.utils.IPUtil;
import com.youhome.utils.StringUtil;
import com.youhome.utils.TokenUtils;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.*;

@Aspect
@Configuration
@Slf4j
public class HttpAspect {

    @Autowired
    private UserService bUserService;

    @Autowired
    private LogService bLogService;

    @Autowired
    private TokenService tokenService;

    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     */
    public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";

        for (Method method : methods) {
            if (method.isAnnotationPresent(ApiOperation.class)) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == arguments.length) {
                        description = method.getAnnotation(ApiOperation.class).value();
                        break;
                    }
                }
            }
        }
        return description;
    }

    @Pointcut("execution(public * com.youhome.controller.*.*(..))")
    public void log() {

    }

    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            User user = new User();
            HttpServletRequest request = attributes.getRequest();
            String authorization = request.getHeader("Authorization");
            if (authorization != null && authorization.startsWith("Bearer ")) {
                String token = authorization.substring("Bearer ".length());
                if(!StringUtils.isEmpty(token)) {
                    if (TokenUtils.isExpired(token)) {
                        if (tokenService.checkToken(token)) {
                            Claims claims = TokenUtils.parserToken(token);
                            if (!claims.isEmpty()) {
                                String openid = (String) claims.get("openid");
                                if (!StringUtils.isEmpty(openid)) {
                                    user = bUserService.getCurrentUser(openid);
                                }
                            }
                        }
                    }
                }
            }

            Log sysLog = new Log();
            //domain

            String url = request.getRequestURL().toString();
            try {
                url = URLDecoder.decode(url, "UTF-8");

                sysLog.setUrl(url);
                //logger.info("domain={}", domain);
                //method
                String method = request.getMethod().toString();
                sysLog.setMethod(method);
                //logger.info("method={}", request.getMethod());
                //ip
                String ip = new IPUtil().getRemoteAddrIp(request);//request.getRemoteAddr().toString();
                sysLog.setIp(ip);
                //logger.info("ip={}", ip);

                //类方法
                String class_method = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
                sysLog.setClassMethod(class_method);
                //logger.info("class_method={}", class_method);

                //方法描述
                String description = getControllerMethodDescription(joinPoint);
                //logger.info(description);
                sysLog.setDescription(description);

                //参数
                Enumeration<String> enu = request.getParameterNames();
                List<String> parameters = new ArrayList<>();
                while (enu.hasMoreElements()) {
                    String paraName = (String) enu.nextElement();
                    parameters.add(paraName + "=" + request.getParameter(paraName));
                }

                //logger.info("parameters={}", StringUtils.join(parameters, "&"));
                if (parameters != null && parameters.size() > 0) {
                    sysLog.setParams(StringUtils.join(parameters, "&"));
                }

                //用户
                if (user != null) {
                    sysLog.setUserId(user.getUserId());
                    //logger.info("user={}", user.toString());
                }
                sysLog.setCreateTime(new Date());
                sysLog.setSource("小程序API");

                bLogService.insertSelective(sysLog);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    @After("log()")
    public void doAfter() {
        //logger.info("doAfter");
    }

    @AfterReturning(returning = "object", pointcut = "log()")
    public void doAfterReturning(JoinPoint joinPoint, Object object) {

    }
}
